package com.kou.backend.config;

import com.kou.backend.filter.RequestJwtTokenFilter;
import com.kou.backend.handler.BackendAccessDeniedHandler;
import com.kou.backend.handler.BackendAuthenticationEntryPoint;
import com.kou.backend.handler.LogoutHandler;
import com.kou.backend.service.UserInfoService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;


/**
 * Security配置
 *
 * @author: Chaojie.Kou
 * @since: 2024/11/14 16:44
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private BackendAccessDeniedHandler backendAccessDeniedHandler;
    @Resource
    private BackendAuthenticationEntryPoint backendAuthenticationEntryPoint;
    @Resource
    private LogoutHandler logoutHandler;

    /**
     * PasswordEncoder
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new SecurityPasswordEncoder();
    }

    static class SecurityPasswordEncoder implements PasswordEncoder {
        /**
         * 不使用Security的密码验证
         *
         * @return **
         */
        @Override
        public String encode(CharSequence rawPassword) {
            return "**";
        }

        @Override
        public boolean matches(CharSequence rawPassword, String encodedPassword) {
            return true;
        }
    }

    /**
     * 获取当前登录用户信息
     */
    public UserDetails currentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return (UserDetails) authentication.getPrincipal();
    }

    /**
     * 注入jwt验证授权过滤器
     */
    @Bean
    public RequestJwtTokenFilter jwtAuthenticationTokenFilter() {
        return new RequestJwtTokenFilter();
    }

    @Bean
    public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return userAccount -> userInfoService.loadUserByUserId(userAccount);
    }

    /**
     * 配置过滤器链
     *
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable() // 禁用 CSRF
                .authorizeHttpRequests()
                .and()
                .sessionManagement()// 基于token，所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .logout()
                .logoutUrl("/v1/api/user/logout")
                .deleteCookies("JSESSIONID")
                .logoutSuccessHandler(logoutHandler)
                .and().authorizeHttpRequests()
                // 指定的接口直接放行
                // swagger
                .requestMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/swagger-resources/**")
                .permitAll()
                .requestMatchers("/v1/api/user/login", "/v1/api/user/logout")// 对登录登出要允许匿名访问
                .permitAll()
                .requestMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
                .permitAll()
                .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/v2/**", "/api/**")
                .permitAll() //放行swagger
                // 其他的接口都需要认证后才能请求
                .anyRequest().authenticated();
        //禁用缓存
        http.headers().cacheControl();
        //添加 自定义 jwt Filter
        http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        http.exceptionHandling()
                .accessDeniedHandler(backendAccessDeniedHandler)
                .authenticationEntryPoint(backendAuthenticationEntryPoint);

        return http.build();
    }
}
